<script lang="jsx">
import { defineComponent, unref, ref, onActivated, watch, computed, nextTick } from 'vue'
import {
  initRemoteValues,
  getGridDefaultValue,
  getGridFields,
  getMergeGridFields,
  initForeignValues
} from '../utils/table'
import GridItem from './item.vue'
import GridQuery from './query.vue'
import { getFormValues } from '@/api/basic'
import { debounce, template } from 'lodash-es'
import func from './func'
import { loadOneMethod, initAllTreeSelectData } from './tool'
import { isNullOrUnDef } from '@/utils/is'
import dayjs from 'dayjs'
import { useAppStore } from '@/store/modules/app'

export default defineComponent({
  name: 'AutoGrid',
  props: {
    modelValue: {
      type: Object,
      default: () => ({})
    },
    readonly: {
      type: Boolean,
      default: () => false
    },
    // 页面grid配置
    page: {
      type: Object,
      default: () => ({})
    },
    // fields字段配置
    fields: {
      type: Array,
      default: () => []
    },
    // operators按钮配置
    operators: {
      type: Array,
      default: () => []
    },
    // datas常量配置
    datas: {
      type: Object,
      default: () => ({})
    },
    // form还是query
    module: {
      type: String,
      default: () => ''
    },
    // 是否自定义页面用
    isCustom: {
      type: Boolean,
      default: () => false
    }
  },
  emits: ['update:modelValue', 'enter', 'search'],
  setup(props, { emit, expose, slots }) {
    const page = unref(props.page)
    const fields = unref(props.fields)
    const operators = unref(props.operators)
    const datas = unref(props.datas)
    const form = getGridDefaultValue(page)
    const module = page.module || props.module
    const appStore = useAppStore()

    // 初始化form的值（查询条件form不初始化）
    if (!module?.includes('query')) {
      fields.forEach((fd) => {
        if (fd.value !== null && fd.value !== undefined) {
          form[fd.key] = fd.value
        }
      })
    }
    const model = computed({
      get() {
        if (Object.keys(props.modelValue) < 1) {
          emit('update:modelValue', form)
        }
        Object.keys(form).forEach((key) => {
          if (
            (props.modelValue[key] === null || props.modelValue[key] === undefined) &&
            props.modelValue[key] !== form[key]
          ) {
            // eslint-disable-next-line vue/no-mutating-props
            props.modelValue[key] = form[key]
          }
        })
        return props.modelValue
      },
      set(val) {
        emit('update:modelValue', val)
      }
    })

    console.log('=====>', page, fields, model.value)

    const debounceValues = debounce(function () {
      const gridFields = getGridFields(page, model.value)
      // form表单只显示一条下拉框，点击下拉框的时候才去加载
      fields
        .filter(
          (col) =>
            !['enum', 'list', 'tree-select', 'tree-select-multiple'].includes(col.type) &&
            col.source &&
            gridFields.some((x) => x.value && x.field === col.key)
        )
        .forEach((col) => {
          loadOneMethod(col, model.value)
        })
      // initForeignValues([model.value], fields, gridFields)
    }, 300)

    watch(
      () => props.modelValue,
      (val) => {
        if (val || Object.keys(val)?.length) {
          // 列表页已经查询了所有下拉数据，暂时去掉
          debounceValues()
        }
      },
      { immediate: true }
    )

    // page配置的watch，触发更新字段
    const debounceUpdate = debounce(function (wt) {
      Object.keys(wt.results).forEach((k) => {
        try {
          const compiled = template(wt.results[k])
          model.value[k] = compiled({ ...model.value, $dayjs: dayjs })
        } catch (e) {}
      })
    }, 300)
    // 配置watch，触发更新字段
    if (page.watch) {
      ;[page.watch].flat().forEach((wt) => {
        watch(
          () => wt.fields.map((k) => model.value[k]),
          () => {
            debounceUpdate(wt)
          }
        )
      })
    }

    const formRef = ref(null)
    // 校验表单
    const validate = (callback) => {
      formRef.value?.validate(async (valid) => {
        if (typeof callback === 'function') {
          callback(valid)
        }
      })
    }
    // 清理表单校验
    const resetFields = async () => {
      return new Promise((resolve) => {
        nextTick(() => {
          formRef.value?.resetFields()
          resolve(true)
        })
      })
    }
    // 重置表单数据
    const resetForm = async () => {
      return resetFields()
    }
    // 是否批量提交
    const getBatchList = () => {
      return []
    }

    // 触发执行func
    const debounceExec = debounce(function (col) {
      const result = func[col.exec?.func](model.value[col.key])
      if (result !== model.value[col.key]) {
        model.value[col.key] = result
      }
    }, 300)
    // 配置有exec属性，当值变化时，执行func方法
    const execFields = fields.filter((c) => !!c.exec?.func)
    execFields.forEach((col) => {
      watch(
        () => model.value[col.key],
        (v) => {
          if (v) {
            debounceExec(col)
          }
        }
      )
    })

    // 自定义页面在外边自己处理数据
    if (!props.isCustom) {
      // 配置有source字段的，请求接口数据
      // initRemoteValues(fields);
      // const sourceFields = fields.filter((f) => f.source);
      // sourceFields.forEach((s) => {
      //   if (!s.values || s.values.length < 1) {
      //     getFormValues(
      //       typeof s.source === "string" ? { source: s.source } : s.source
      //     ).then(({ values }) => {
      //       s.values = values;
      //     });
      //   }
      // });
    }

    expose({ validate, resetFields, resetForm, getBatchList })

    // 自动触发validate
    const validateCustom = (rule, value, callback) => {
      const field = fields.find((f) => f.key === rule.field)
      const require = field.required || field.require
      if (
        field &&
        require &&
        typeof require === 'object' &&
        [require]
          .flat()
          .some(
            (vis) => model.value && Object.keys(vis).every((key) => model.value[key] == vis[key])
          )
      ) {
        if (value === undefined || value === null || value === '') {
          callback(new Error('请输入'))
        } else {
          callback()
        }
      }
      callback()
    }
    // 正则校验
    const validateRegex = (rule, value, callback) => {
      const field = fields.find((f) => f.key === rule.field)
      const validate = field.validate
      // 正则表达式字符串
      const pattern = validate?.regex || validate?.pattern
      const message = validate?.message
      if (pattern) {
        var regex = new RegExp(pattern)
        if (!regex.test(value)) {
          callback(new Error(message))
        } else {
          callback()
        }
      } else {
        callback()
      }
    }
    // 触发validate
    // const debounceValidRequire = debounce(function (field) {
    //   formRef.value?.validateField(field);
    // }, 300);
    if (!module?.includes('query')) {
      // 监控有关联require的字段变化，触发validate
      fields
        .filter((field) => {
          const require = field.required || field.require
          return typeof require === 'object'
        })
        .forEach((f) => {
          ;[f.require || f.required]
            .flat()
            .map((o) => Object.keys(o))
            .flat()
            .forEach((req) => {
              watch(
                () => [f.key, model.value[req]],
                (val) => {
                  formRef.value?.validateField(val[0])
                }
              )
            })
        })
    }

    // 触发更新字段
    // const debounceWatchUpdate = debounce(function (colWatch, value) {
    //   [colWatch].flat().forEach((one) => {
    //     if ([one.value].flat().includes(value)) {
    //       model.value[one.field] = one.fieldValue;
    //     } else if (!isNullOrUnDef(one.fieldElseValue)) {
    //       model.value[one.field] = one.fieldElseValue;
    //     }
    //   });
    // }, 300);
    // // 配置有watch，当字段值变化时修改目标值
    // fields
    //   .filter((c) => !!c.watch)
    //   .forEach((col) => {
    //     watch(
    //       () => model.value[col.key],
    //       (v) => {
    //         debounceWatchUpdate(col.watch, v);
    //       }
    //     );
    //   });
    // 获取校验配置
    const getValidateConfig = (c) => {
      const results = []
      if (c.required === 'object' || typeof c.require === 'object') {
        results.push({
          validator: validateCustom,
          message:
            ([
              'enum',
              'list',
              'range',
              'checkbox',
              'radio',
              'date',
              'datetime',
              'cascader',
              'cascader-select',
              'tree-select',
              'tree-select-multiple'
            ].includes(c.type)
              ? '请选择'
              : '请输入') + c.name,
          trigger: [
            'enum',
            'list',
            'range',
            'checkbox',
            'radio',
            'date',
            'datetime',
            'cascader',
            'cascader-select',
            'tree-select',
            'tree-select-multiple'
          ].includes(c.type)
            ? ['change', 'blur']
            : 'blur'
        })
      } else {
        results.push({
          required: true,
          message:
            ([
              'enum',
              'list',
              'range',
              'checkbox',
              'radio',
              'date',
              'datetime',
              'cascader',
              'cascader-select',
              'tree-select',
              'tree-select-multiple'
            ].includes(c.type)
              ? '请选择'
              : '请输入') + c.name,
          trigger: [
            'enum',
            'list',
            'range',
            'checkbox',
            'radio',
            'date',
            'datetime',
            'cascader',
            'cascader-select',
            'tree-select',
            'tree-select-multiple'
          ].includes(c.type)
            ? ['change', 'blur']
            : 'blur'
        })
      }
      if (c.validate && typeof c.validate === 'object') {
        results.push({
          validator: validateRegex,
          message: c.validate.message,
          trigger: ['blur']
        })
      }
      return results
    }
    return () => {
      switch (module) {
        case 'form': {
          const rules = getMergeGridFields(page, fields)
            .filter((f) => f.required || f.require || f.validate)
            .reduce((t, c) => {
              // 级联选择用第一个字段作为校验
              if (c.type === 'cascader-select') {
                const firstField = c.configs?.[0]?.field
                if (firstField) {
                  t[firstField] = getValidateConfig(c)
                }
              } else {
                t[c.key || c.field] = getValidateConfig(c)
              }
              return t
            }, {})
          return (
            <el-form
              ref={formRef}
              model={model}
              rules={rules}
              inline={true}
              disabled={props.readonly}
              style={page.style}
              class={`auto-grid form-grid ${page.class || ''}`}
              label-position={appStore.getMobile ? 'top' : undefined}
              {...page.config}
            >
              <GridItem
                model={module === 'form' ? model : undefined}
                page={page}
                grid={page.grid}
                fields={fields}
                operators={operators}
                datas={datas}
                emitFun={emit}
              ></GridItem>
              {slots['default'] && (
                <div class="el-form-item el-form-item--default">
                  {slots['default'](model.value)}
                </div>
              )}
            </el-form>
          )
        }
        case 'query': {
          const rules = []
          return (
            <el-form
              ref={formRef}
              model={model}
              rules={rules}
              inline={true}
              size={'default'}
              disabled={props.readonly}
              style={page.style}
              class={`auto-grid query-grid ${page.class || ''}`}
              label-position={appStore.getMobile ? 'top' : undefined}
              {...page.config}
            >
              <GridQuery
                model={module === 'query' ? model : undefined}
                page={page}
                grid={page.grid}
                fields={fields}
                operators={operators}
                datas={datas}
                emitFun={emit}
              ></GridQuery>
              {slots['default'] && (
                <div class="el-form-item el-form-item--default">
                  {slots['default'](model.value)}
                </div>
              )}
            </el-form>
          )
        }
        default:
          return (
            <el-form
              ref={formRef}
              model={model}
              inline={true}
              size={'default'}
              disabled={props.readonly}
              style={page.style}
              class={`auto-grid ${page.class || ''}`}
              {...page.config}
            >
              <GridQuery
                model={model}
                page={page}
                grid={page.grid}
                fields={fields}
                operators={operators}
                datas={datas}
                emitFun={emit}
              ></GridQuery>
              {slots['default'] && (
                <div class="el-form-item el-form-item--default">
                  {slots['default'](model.value)}
                </div>
              )}
            </el-form>
          )
      }
    }
  }
})
</script>
